package com.lsh.config;

import com.lsh.interceptor.MyAccessDeniedHandler;
import com.lsh.interceptor.MyAuthenticationFailureHandler;
import com.lsh.interceptor.MyAuthenticationSuccessHandler;
import com.lsh.interceptor.MyLogoutSuccessHandler;
import com.lsh.service.Impl.MyPermissionEvaluatorImpl;
import com.lsh.service.Impl.MyUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;

/**
 * @author ：LiuShihao
 * @date ：Created in 2020/11/3 10:45 上午
 * @desc ：
 */
// 配置类注解
@Configuration
// 开启 Security 服务
@EnableWebSecurity
//开启全局 Securtiy 注解。
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     *  注入自定义认证类
     */
    @Autowired
    @Qualifier("userDetailsService")
    private MyUserDetailsServiceImpl userDetailsService;

    @Autowired
    @Qualifier("myAccessDeniedHandler")
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Autowired
    @Qualifier("myAuthenticationSuccessHandler")
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Autowired
    @Qualifier("myAuthenticationFailureHandler")
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    @Autowired
    private SessionRegistry sessionRegistry ;

    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;




    /**
     * 密码的转码解码   密码未加密
     * @param auth
     * @throws Exception
     */
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
//            @Override
//            public String encode(CharSequence charSequence) {
//                return charSequence.toString();
//            }
//            @Override
//            public boolean matches(CharSequence charSequence, String s) {
//                return s.equals(charSequence.toString());
//            }
//        });
//    }

    /**
     * 如果密码加密，则使用这种方法
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }
    /**
     * 定义具体的路径资源对应的权限
     *  authorizeRequests所有security全注解配置实现的开端，表示开始说明需要的权限。
     *  需要的权限分两部分，第一部分是拦截的路径，第二部分访问该路径需要的权限。
     *  antMatchers表示拦截什么路径，permitAll任何权限都可以访问，直接放行所有。
     *  anyRequest()任何的请求，authenticated认证后才能访问
     */

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                // 如果有允许匿名的url，填在下面
                .antMatchers("/anon").permitAll()
                .antMatchers("/addSysUser").permitAll()
                .antMatchers("/login/invalid").permitAll()
                //  /admin资源需要ROLE_ADMIN角色才能访问
//                .antMatchers("/admin").hasRole("ADMIN")
                //  /user 资源需要有ROLE_USER才能访问
//                .antMatchers("/user").hasRole("USER")
                //释放静态资源
                .antMatchers("/js/**","/css/**","/images/*","/fonts/**","/**/*.png","/**/*.jpg").permitAll()
                // 所有请求都需要认证后才能访问
                .anyRequest().authenticated()
                .and()
                //注入 无权异常处理类
                .exceptionHandling().accessDeniedHandler(myAccessDeniedHandler)
                .and()
                //即 failureUrl() 指定认证失败后Url，defaultSuccessUrl() 指定认证成功后Url。
                // 我们可以通过设置 successHandler() 和 failureHandler() 来实现自定义认证成功、失败处理。
                // 设置登陆页 路径
                .formLogin().loginPage("/login")
                .successHandler(myAuthenticationSuccessHandler)
                .failureHandler(myAuthenticationFailureHandler)
                .permitAll()
                // 设置登陆成功 的请求路径
//                .defaultSuccessUrl("/")
                //设置失败 的请求路径
//                .failureUrl("/login")
                // 自定义登陆用户名和密码参数，默认为username和password
//                .usernameParameter("username")
//                .passwordParameter("password")
                .and()
                .logout()
                .logoutSuccessHandler(myLogoutSuccessHandler);
                //在session退出时调用
//                .and()
//                .sessionManagement()
//                .invalidSessionUrl("/login/invalid")
//                .maximumSessions(1)
//                // 当达到最大值时，是否保留已经登录的用户
////                .maxSessionsPreventsLogin(false)
//                .maxSessionsPreventsLogin(true)
//                // 当达到最大值时，旧用户被踢出后的操作
//                .expiredSessionStrategy(new MySessionInformationExpiredStrategy())
//                .sessionRegistry(sessionRegistry);

                // 关闭CSRF跨域
                http.csrf().disable();
    }
    /**
     * 设置拦截忽略文件夹，可以对静态资源放行  与上边的一样 用那个都可以：
     * @param web
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        // 忽略URL
        web.ignoring().antMatchers("/**/*.js", "/image/*.jepg", "/**/*.css", "/**/*.js", "/**/*.map", "/**/*.html",
                "/**/*.png");
    }


    /**
     * 注入自定义PermissionEvaluator
     */
    @Bean
    public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler(){
        DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(new MyPermissionEvaluatorImpl());
        return handler;
    }


}

